/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.testile.dataset.sqlscript;

import java.io.Reader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author hudimar
 */
public class SqlScriptEngine extends AbstractScriptEngine {

	public static final String DB_CONNECTION = "dbConnection";
	Logger logger = LoggerFactory.getLogger(SqlScriptEngine.class);

	public Bindings createBindings() {
		return new SimpleBindings();
	}

	public Object eval(String script, ScriptContext context) throws ScriptException {
		logger.debug("SQL Script: {}", script);
		try {
			return runSQL(script, getConnection(context));
		} catch (SQLException ex) {
			throw new ScriptException(ex);
		}
	}

	public Object eval(Reader reader, ScriptContext context) throws ScriptException {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	public ScriptEngineFactory getFactory() {
		return new SqlScriptEngineFactory();
	}

	private Connection getConnection(ScriptContext context){
		Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
		Object o = bindings.get(DB_CONNECTION);
		Connection connection;

		if(o == null) {
			throw new IllegalStateException("SQL Connection not found in ScriptContext under property '" +  DB_CONNECTION + "' (SqlScriptEngine.DB_CONNECTION).");
		}

		if(!(o instanceof Connection)) {
			throw new IllegalStateException("java.sql.Connection object not found in ScriptContext under property '" + DB_CONNECTION + "' (SqlScriptEngine.DB_CONNECTION). Found '" + o.getClass() + "'");
		}

		connection = (Connection)o;
		try {
			if (connection.isClosed()) {
				throw new IllegalStateException("Connection is closed.");
			}
		} catch (SQLException ex) {
			logger.error("Exception: "+ex.getMessage()+", state: "+ex.getSQLState());
			throw new IllegalStateException(ex);
		}

		return connection;
	}

	private Object runSQL(String sql, Connection connection) throws SQLException {
		PreparedStatement statement = connection.prepareStatement(sql);
		ResultSet result = statement.executeQuery();
		if(result.next()){
			return result.getObject(1);
		}else{
			throw new SQLException("No row selected for SQL query: '"+sql+"'.");
		}
	}
}
